package org.example.lib;

import lombok.extern.slf4j.Slf4j;
import org.example.annotations.component.Aspect;
import org.example.annotations.component.Controller;
import org.example.annotations.component.Service;
import org.example.annotations.route.GetMapping;
import org.example.annotations.route.PostMapping;
import org.example.annotations.route.RequestMapping;
import org.example.lib.utils.ClassHelper;
import org.reflections.Reflections;

import java.lang.reflect.Method;


@Slf4j
public class Scanner {

    private final String[] packages;
    private final IocContainer iocContainer = IocContainer.instance;
    private final Router router = Router.instance;

    private Scanner(String[] packages) {
        this.packages = packages;
    }

    public static void scanBane(String[] packages){
        new Scanner(packages).scan();
    }

    public void scan() {
        try {
            for (String packageName : packages) {
                Reflections reflections = new Reflections(packageName);

                collectBeans(reflections.getTypesAnnotatedWith(Controller.class));
                collectBeans(reflections.getTypesAnnotatedWith(Service.class));
                collectBeans(reflections.getTypesAnnotatedWith(Aspect.class));

                for (Class<?> aClass : reflections.getTypesAnnotatedWith(Controller.class)) {
                    for (Method method : aClass.getMethods()) {
                        GetMapping     getMapping     = method.getAnnotation(GetMapping.class);
                        PostMapping    postMapping    = method.getAnnotation(PostMapping.class);
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        if (getMapping != null){
                            Route route = new Route(getMapping.value());
                            route.setMethod(method);
                            router.addRoute(route, RequestMapping.HttpMethod.GET);
                        }
                        if (postMapping != null) {
                            Route route = new Route(postMapping.value());
                            route.setMethod(method);
                            router.addRoute(route, RequestMapping.HttpMethod.POST);
                        }
                        if (requestMapping != null) {
                            for (RequestMapping.HttpMethod httpMethod : requestMapping.method()) {
                                Route route = new Route(requestMapping.value());
                                route.setMethod(method);
                                router.addRoute(route, httpMethod);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("Error scanning packages", e);
        }
    }

    private void collectBeans(Iterable<Class<?>> classes) {
        for (Class<?> aClass : classes) {
            if (!ClassHelper.isInstantiable(aClass)){
                continue;
            }

            iocContainer.registerDependency(aClass, ClassHelper.getDependence(aClass));
            for (Class<?> anInterface : aClass.getInterfaces()) {
                iocContainer.registerInterface(anInterface, aClass);
            }
        }
    }
}
